package com.example.OpenGLES320;

import android.content.Context;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;

import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.Matrix;

public class GLRender implements Renderer {

    private final String LOG_TAG = "GLRender";
    private int[] vaoIds = new int[1];  // 用于存储 VAO ID
    private int[] vboIds = new int[2];
    private int shaderProgramId;        // 着色器 ID
    private FloatBuffer boxVerticesBuffer;

    private float[] m_modelMatrix = new float[16];
    private float[] m_viewMatrix = new float[16];
    private float[] m_projectionMatrix = new float[16];

    public int width = 1920;
    public int height = 1080;


    private final String vsCode = "#version 300 es\n" +
            "layout(location = 0) in vec3 a_Position;\n" +
            "layout(location = 1) in vec3 a_Color;\n" +
            "uniform mat4 u_ModelMatrix;\n" +
            "uniform mat4 u_ViewMatrix;\n" +
            "uniform mat4 u_ProjMatrix;\n" +
            "out vec3 v_color;\n" +
            "void main() {\n" +
            "    v_color = a_Color;\n" +
            "    gl_Position = u_ProjMatrix * u_ViewMatrix * u_ModelMatrix * vec4(a_Position, 1.0);\n" +
            "}";
    private final String fsCode = "#version 300 es\n" +
            "precision mediump float;\n" +
            "out vec4 fragColor;\n" +
            "in vec3 v_color;\n" +
            "void main() {\n" +
            "    fragColor = vec4(v_color, 1.0); \n" +
            "}";

    public GLRender(Context context)
    {

    }

    @Override
    public void onDrawFrame(GL10 gl)
    {
        drawFrame();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height)
    {
        Log.i(LOG_TAG, "onSurfaceChanged:: w: " + width + " h: " + height);
        this.width = width;
        this.height = height;
        GLES30.glViewport(0,0,width,height);
    }

    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        Log.i(LOG_TAG, "opengl version: " + gl10.glGetString(GL10.GL_VERSION));

        GLES30.glClearColor(0.2F, 0.2F, 0.2F, 1.0F);      // 不要不写小数点！否则会没用。
        GLES30.glEnable(GL10.GL_DEPTH_TEST);
         GLES30.glEnable(GL10.GL_CULL_FACE);

        initResources();
    }

    /**
     * @brief 生成顶点数据
     */
    private void generateVertices()
    {
        boxVerticesBuffer = GLBufferWrapper.WrapFloat(new float[]{
                // position             // color
                -1.0f, -1.0f, -1.0f,    1.0f, 0.0f, 0.0f,
                1.0f, -1.0f, -1.0f,     1.0f, 0.0f, 0.0f,
                1.0f,  1.0f, -1.0f,     1.0f, 0.0f, 0.0f,
                1.0f,  1.0f, -1.0f,     1.0f, 0.0f, 0.0f,
                -1.0f,  1.0f, -1.0f,    1.0f, 0.0f, 0.0f,
                -1.0f, -1.0f, -1.0f,    1.0f, 0.0f, 0.0f,

                -1.0f, -1.0f,  1.0f,    0.0f, 1.0f, 0.0f,
                1.0f, -1.0f,  1.0f,     0.0f, 1.0f, 0.0f,
                1.0f,  1.0f,  1.0f,     0.0f, 1.0f, 0.0f,
                1.0f,  1.0f,  1.0f,     0.0f, 1.0f, 0.0f,
                -1.0f,  1.0f,  1.0f,    0.0f, 1.0f, 0.0f,
                -1.0f, -1.0f,  1.0f,    0.0f, 1.0f, 0.0f,

                -1.0f,  1.0f,  1.0f,    0.0f, 1.0f, 0.0f,
                -1.0f,  1.0f, -1.0f,    0.0f, 1.0f, 0.0f,
                -1.0f, -1.0f, -1.0f,    0.0f, 1.0f, 0.0f,
                -1.0f, -1.0f, -1.0f,    0.0f, 1.0f, 0.0f,
                -1.0f, -1.0f,  1.0f,    0.0f, 1.0f, 0.0f,
                -1.0f,  1.0f,  1.0f,    0.0f, 1.0f, 0.0f,

                1.0f,  1.0f,  1.0f,     0.0f, 0.0f, 1.0f,
                1.0f,  1.0f, -1.0f,     0.0f, 0.0f, 1.0f,
                1.0f, -1.0f, -1.0f,     0.0f, 0.0f, 1.0f,
                1.0f, -1.0f, -1.0f,     0.0f, 0.0f, 1.0f,
                1.0f, -1.0f,  1.0f,     0.0f, 0.0f, 1.0f,
                1.0f,  1.0f,  1.0f,     0.0f, 0.0f, 1.0f,

                -1.0f, -1.0f, -1.0f,    0.0f, 1.0f, 1.0f,
                1.0f, -1.0f, -1.0f,     0.0f, 1.0f, 1.0f,
                1.0f, -1.0f,  1.0f,     0.0f, 1.0f, 1.0f,
                1.0f, -1.0f,  1.0f,     0.0f, 1.0f, 1.0f,
                -1.0f, -1.0f,  1.0f,    0.0f, 1.0f, 1.0f,
                -1.0f, -1.0f, -1.0f,    0.0f, 1.0f, 1.0f,

                -1.0f,  1.0f, -1.0f,    0.3f, 0.8f, 0.4f,
                1.0f,  1.0f, -1.0f,     0.3f, 0.8f, 0.4f,
                1.0f,  1.0f,  1.0f,     0.3f, 0.8f, 0.4f,
                1.0f,  1.0f,  1.0f,     0.3f, 0.8f, 0.4f,
                -1.0f,  1.0f,  1.0f,    0.3f, 0.8f, 0.4f,
                -1.0f,  1.0f, -1.0f,    0.3f, 0.8f, 0.4f,
        });
    }

    /**
     * @brief 初始化opengl es所需资源
     */
    private void initResources()
    {
        // 生成顶点数据
        generateVertices();

        // 绑定顶点数据
        GLES30.glGenVertexArrays(1, vaoIds, 0); // 生成 VAO
        GLES30.glBindVertexArray(vaoIds[0]);    // 绑定 VAO

        GLES30.glGenBuffers(1, vboIds, 0);
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboIds[0]);
        GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, boxVerticesBuffer.capacity() * Float.BYTES, boxVerticesBuffer, GLES30.GL_STATIC_DRAW);

        GLES30.glEnableVertexAttribArray(0);
        GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 6 * Float.BYTES, 0);
        GLES30.glEnableVertexAttribArray(1);
        GLES30.glVertexAttribPointer(1, 3, GLES30.GL_FLOAT, false, 6 * Float.BYTES, 0);

        // 生成并编译着色器
        shaderProgramId = createAndCompileShaders(vsCode, fsCode);
    }

    /**
     * @brief 绘制一帧
     */
    private void drawFrame()
    {
        GLES30.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

        // 使用着色器程序
        GLES30.glUseProgram(shaderProgramId);

        // 设置模型矩阵
        Matrix.setIdentityM(m_modelMatrix, 0);
        Matrix.translateM(m_modelMatrix, 0, 0.0f, 0.0f, 0.0f);
        Matrix.rotateM(m_modelMatrix,0, 45.0f, 0.0f, 0.0f, 1.0f);
        Matrix.rotateM(m_modelMatrix,0, 30.0f, 0.0f, 1.0f, 0.0f);
        GLUniformManager.instance().setUniformMatrix4fv(shaderProgramId, "u_ModelMatrix", m_modelMatrix);

        // 设置视图矩阵
        Matrix.setLookAtM(m_viewMatrix, 0,
                0.0f,0.0f,10.0f,
                0.0f,0.0f, 0.0f,
                0,1,0);
        // Matrix.setIdentityM(m_viewMatrix, 0);
        GLUniformManager.instance().setUniformMatrix4fv(shaderProgramId, "u_ViewMatrix", m_viewMatrix);

        Matrix.perspectiveM(m_projectionMatrix, 0,
                60.0f, (float)width/height,
                0.5f, 100.f);
        GLUniformManager.instance().setUniformMatrix4fv(shaderProgramId, "u_ProjMatrix", m_projectionMatrix);

        // 绘制
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 36);
    }

    /**
     * @brief 创建并编译着色器程序
     * @return 着色器ID
     */
    private int createAndCompileShaders(String vsCode, String fsCode) {

        int vertexShader = loadShader(GLES30.GL_VERTEX_SHADER, vsCode);
        int fragmentShader = loadShader(GLES30.GL_FRAGMENT_SHADER, fsCode);

        // 创建程序并链接
        int programId = GLES30.glCreateProgram();
        GLES30.glAttachShader(programId, vertexShader);
        GLES30.glAttachShader(programId, fragmentShader);
        GLES30.glLinkProgram(programId);

        // 清理着色器
        GLES30.glDeleteShader(vertexShader);
        GLES30.glDeleteShader(fragmentShader);

        return programId;
    }

    private int loadShader(int type, String shaderCode) {
        int shader = GLES30.glCreateShader(type);
        GLES30.glShaderSource(shader, shaderCode);
        GLES30.glCompileShader(shader);

        // 检查编译状态
        int[] compiled = new int[1];
        GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compiled, 0);
        if (compiled[0] == 0) {
            String error = GLES30.glGetShaderInfoLog(shader);
            GLES30.glDeleteShader(shader); // 销毁着色器
            throw new RuntimeException("Error compiling shader: " + error);
        }

        return shader;
    }

}